package pers.bc.utils.pub;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.io.Serializable;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;

import com.alibaba.fastjson.JSONObject;

import pers.bc.utils.constant.IPubCons;
import pers.bc.utils.constant.IPubEvnCons;

/**
 * 不需要导入外部包，自行编写的json字符串转map工具类
 * 
 * @version 1.0<br>
 * @qualiFild pers.bc.utils.pub.JsonUtil.java<br>
 * @author：licheng<br>
 * @date Created on 2018年4月4日<br>
 */
public class JsonUtil extends JSONObject implements IPubEvnCons
{
    /** @date 2018年5月12日 */
    private static final long serialVersionUID = 6115155490383289092L;
    
    private static ThreadLocal<JsonUtil> jsonUtil = new ThreadLocal<JsonUtil>();
    
    public static Map<String, String> uri2Map(String urlPram)
    {
        return convertUri2Map(urlPram);
    }
    
    public static Map<String, String> convertUri2Map(String urlPram)
    {
        Map<String, String> params = new HashMap<>();
        if (urlPram == null || urlPram.isEmpty())
        {
            return params;
        }
        
        String[] pairs = urlPram.split("&");
        for (String pair : pairs)
        {
            int idx = pair.indexOf("=");
            try
            {
                String key =
                    (idx > 0) ? URLDecoder.decode(pair.substring(0, idx), PubEnvUtil.UTF_8) : URLDecoder.decode(pair, PubEnvUtil.UTF_8);
                
                String value = (idx > 0 && pair.length() > idx + 1) ? URLDecoder.decode(pair.substring(idx + 1), PubEnvUtil.UTF_8) : "";
                if (PubEnvUtil.isNotEmptyObj(params.get(key)))
                {
                    String temp = params.get(key);
                    params.put(key, temp + COMMA + value);
                }
                else
                    params.put(key, value);
            }
            catch (Exception e)
            {
                // 处理解码异常（通常不会发生，因使用StandardCharsets）
                throw new IllegalArgumentException("Failed to decode parameter: " + pair, e);
            }
        }
        
        return params;
    }
    
    public static JsonUtil getInstance()
    {
        JsonUtil df = jsonUtil.get();
        if (null == df)
        {
            synchronized (JsonUtil.class)
            {
                if (null == df)
                {
                    df = new JsonUtil();
                    jsonUtil.set(df);
                }
            }
        }
        return df;
    }
    
    /*************************************************************
     * <br>
     * 
     * 说明: Obj 转 json <br>
     * 
     * @Description <br>
     * @Date Created on 2022/8/17 21:56 <br>
     * @param obj <br>
     * @return java.lang.String <br>
     * @Author LIBENCHENG
     * @version 1.0 <br>
     *************************************************************          <br>
     */
    public static String transObj2Josn(Object obj) throws Exception
    {
        return CollectionUtil.transObj2Josn(obj);
    }
    
    public static String compressJson(String json)
    {
        return compressJson(json, PubEnvUtil.EMPTY);
    }
    
    /*************************************************************
     * <br>
     * 
     * 说明: 压缩 json<br>
     * 
     * @Description <br>
     * @Date Created on 2022/8/17 21:56 <br>
     * @param json <br>
     * @return java.lang.String <br>
     * @Author LIBENCHENG
     * @version 1.0 <br>
     *************************************************************          <br>
     */
    public static String compressJson(String json, CharSequence replacement)
    {
        if (PubEnvUtil.isEmpty(json)) return EMPTY;
        final StringBuffer bStr = new StringBuffer();
        // Arrays.stream(json.split(PubEnvUtil.COMMA))
        // .forEach(str ->
        // {
        // str = str.replace(PubEnvUtil.SINGLE_QUOTE, PubEnvUtil.EMPTY)
        // .replace(PubEnvUtil.CRLF, PubEnvUtil.EMPTY)
        // .replace(PubEnvUtil.QUOTE, PubEnvUtil.EMPTY)
        // .replace(PubEnvUtil.TAB, PubEnvUtil.EMPTY)
        // // .replace(PubEnvUtil.SPACE, PubEnvUtil.EMPTY)
        // .replace(PubEnvUtil._N, PubEnvUtil.EMPTY).trim();
        // // if (str.contains(PubEnvUtil.LEFT_BRACE) ||
        // str.contains(PubEnvUtil.LEFT_SQ_BRACKET)
        // // || str.contains(PubEnvUtil.RIGHT_BRACE) || str.contains(PubEnvUtil
        // // .RIGHT_SQ_BRACKET))
        // // { str = str.replace(PubEnvUtil.SPACE, PubEnvUtil.EMPTY); }
        //
        // bStr.append(str).append(PubEnvUtil.COMMA);
        // });
        String[] strs = json.split(PubEnvUtil.COMMA);
        for (String str : strs)
        {
            str = str.replace(PubEnvUtil.SINGLE_QUOTE, replacement).replace(PubEnvUtil.CRLF, replacement)
                // .replace(PubEnvUtil.QUOTE, replacement)
                .replace(PubEnvUtil.TAB, replacement)
                // .replace(PubEnvUtil.SPACE, replacement)
                .replace(PubEnvUtil._N, replacement).replace("[]", replacement)
                // 20240613 去转义
                // .replace("\\", PubEnvUtil.EMPTY)
                .trim();
            bStr.append(str).append(PubEnvUtil.COMMA);
        }
        
        return attackColon(StringUtil.toString(bStr.delete(bStr.length() - 1, bStr.length())));
    }
    
    private static String attackColon(String json)
    {
        char[] jsonChar = new char[json.length()];
        Character previous = '0';
        for (int index = 0; index < json.length(); index++)
        {
            char c = json.charAt(index);
            if ((PubEnvUtil.equals(previous, PubEnvUtil.LEFT_BRACE) || PubEnvUtil.equals(previous, PubEnvUtil.COMMA))
                && PubEnvUtil.equals(c, PubEnvUtil.EQUALS))
            {
                jsonChar[index] = ':';
            }
            else
            {
                jsonChar[index] = c;
            }
            if (PubEnvUtil.equals(c, PubEnvUtil.LEFT_BRACE) || PubEnvUtil.equals(c, PubEnvUtil.COMMA)
                || PubEnvUtil.equals(c, PubEnvUtil.EQUALS))
            {
                previous = c;
            }
        }
        
        return String.valueOf(jsonChar);
    }
    
    /*************************************************************
     * <br>
     * 
     * 说明: json 转 map<br>
     * 
     * @Description <br>
     * @Date Created on 2022/8/17 21:57 <br>
     * @param json <br>
     * @return java.lang.String <br>
     * @Author LIBENCHENG
     * @version 1.0 <br>
     *************************************************************          <br>
     */
    public static String json2MapStr(String json)
    {
        return json.replace(PubEnvUtil.LEFT_BRACKET, PubEnvUtil.LEFT_SQ_BRACKET)
            .replace(PubEnvUtil.RIGHT_BRACKET, PubEnvUtil.RIGHT_SQ_BRACKET).replace(PubEnvUtil.COLON, PubEnvUtil.EQUALS)
            .replace(PubEnvUtil.SINGLE_QUOTE, PubEnvUtil.EMPTY);
    }
    
    /**
     * *********************************************************** <br>
     * 说明： 必须首尾是[] <br>
     * 
     * @param ori
     * @return <br>
     * @List<Object> <br>
     * @methods pers.bc.utils.pub.JsonUtilbc#toList <br>
     * @author licheng <br>
     * @date Created on 2020年4月5日 <br>
     * @time 下午8:00:38 <br>
     * @version 1.0 <br>
     *          ************************************************************ <br>
     * @see <br>
     */
    public static List<Map<String, Object>> toList(String ori)
    {
        return getInstance().toListHelp(ori);
    }
    
    public static Map<String, Object> toMap(String ori)
    {
        // ori = removeBlack(ori);
        return getInstance().toMapHelp(ori);
    }
    
    public List<Map<String, Object>> toListHelp(String ori)
    {
        JudgeAssertUtil.checkAssert(PubEnvUtil.isEmpty(ori), "参数不能为空！");
        List<Map<String, Object>> list = new LinkedList<Map<String, Object>>();
        ori = compressJson(ori);
        String[] manyMaps = splitToSingeMap(ori);
        for (String str : manyMaps)
        {
            list.add(toResult(str));
        }
        
        return list;
    }
    
    public Map<String, Object> toMapHelp(String ori)
    {
        JudgeAssertUtil.checkAssert(PubEnvUtil.isEmpty(ori), "参数不能为空！");
        ori = compressJson(ori);
        return toResult(ori);
    }
    
    /**
     * *********************************************************** <br>
     * 说明： 必须首尾是{} <br>
     * 
     * @param ori
     * @return <br>
     * @Map<String,Object> <br>
     * @methods pers.bc.utils.pub.JsonUtilbc#toMapHelp <br>
     * @author licheng <br>
     * @date Created on 2020年4月5日 <br>
     * @time 下午8:01:19 <br>
     * @version 1.0 <br>
     *          ************************************************************ <br>
     * @see <br>
     */
    private Map<String, Object> toResult(String ori)
    {
        if (ori.split(PubEnvUtil.COLON).length < 2)
        // { throw new RuntimeException(ori + "-->不是有效的JSON!"); }
        {
            throw new RuntimeException(ori + "-->不是有效的JSON!");
        }
        
        Map<String, Object> map = new LinkedHashMap<String, Object>();
        String[] manyMaps = splitToSingeMap(ori);
        for (String e : manyMaps)
        {
            int indexOfF = 0;
            int shuangyh = 0;
            for (indexOfF = 0; indexOfF < e.length(); indexOfF++)
            {
                if (e.charAt(indexOfF) == '\"' && shuangyh == 0)
                {
                    shuangyh++;
                    continue;
                }
                if (e.charAt(indexOfF) == '\"' && shuangyh == 1)
                {
                    shuangyh--;
                    continue;
                }
                if (shuangyh == 0 && e.charAt(indexOfF) == ':')
                {
                    break;
                }
            }
            if (indexOfF < e.length() - 1)
            {
                String fieldName = e.substring(0, indexOfF);
                String value = e.substring(indexOfF + 1, e.length());
                if (fieldName.charAt(0) == '\"')
                {// 字符串需要截取
                    fieldName = fieldName.substring(1, fieldName.length() - 1);
                }
                fieldName = fieldName.trim();
                if (value.charAt(0) == '{')
                { // 子map元素
                    if (value.split(PubEnvUtil.COLON).length < 2) map.put(fieldName, value);
                    else
                        map.put(fieldName, toResult(value));
                }
                else if (value.charAt(0) == '[')
                {// 子list元素
                    if (value.split(PubEnvUtil.COLON).length < 2)
                    {
                        String[] singeStrs = splitToSingeMap(value);
                        if (value.contains(PubEnvUtil.COMMA)) map.put(fieldName, Arrays.asList(singeStrs[0].split(PubEnvUtil.COMMA)));
                        else
                            map.put(fieldName, Arrays.asList(singeStrs));
                    }
                    else
                        map.put(fieldName, toListHelp(value));
                }
                else if (value.charAt(0) == '\"')
                {// 字符串元素
                    map.put(fieldName, value.substring(1, value.length() - 1).trim());
                }
                else
                {// 其他元素
                    map.put(fieldName, value.trim());
                }
            }
            else
                map.put(e.substring(0, indexOfF), null);
        }
        return map;
    }
    
    /**
     * *********************************************************** <br>
     * 说明： 必须首尾是{}或者[]<br>
     * 
     * @param ori
     * @return <br>
     * @String[] <br>
     * @methods pers.bc.utils.pub.JsonUtilbc#splitToSingeMap <br>
     * @author licheng <br>
     * @date Created on 2020年4月5日 <br>
     * @time 下午8:00:30 <br>
     * @version 1.0 <br>
     *          ************************************************************ <br>
     * @see <br>
     */
    private String[] splitToSingeMap(String ori)
    {
        if (ori == null)
        {
            return null;
        }
        Map<Integer, Character> indexMap = getCommaIndex(ori);
        
        int lastIndex = 1;// 从第二个，第一个是{
        int lastLeftC = 0;// 左边的{数量，起始是0
        int lastLeftR = 0;// 左边的[数量，起始是0
        int splotLength = 0;// map个数
        int shuangyhao = 0;// 考虑{}有可能在""里面
        List<String> maps = new ArrayList();
        
        lastIndex = 1;// 从第二个，第一个是{
        lastLeftC = 0;// 左边的{数量，起始是0
        int mapIndex = 0;
        for (int index = 0; index < ori.length(); index++)
        {
            char c = ori.charAt(index);
            if (c == '\"' && shuangyhao == 0)
            {
                shuangyhao++;
                continue;
            }
            if (c == '\"' && shuangyhao == 1)
            {
                shuangyhao--;
                continue;
            }
            if (shuangyhao == 1)
            {
                continue;
            }
            if (c == '{')
            {
                lastLeftC++;
                continue;
            }
            if (c == '[')
            {
                lastLeftR++;
                continue;
            }
            if (lastLeftR + lastLeftC == 1 && ((c == ',' && PubEnvUtil.isNotEmptyObj(indexMap.get(index))) || index >= ori.length() - 1))
            {
                maps.add(ori.substring(lastIndex, index).trim());
                lastIndex = index + 1;
                mapIndex++;
            }
            if (c == ']')
            {
                lastLeftR--;
            }
            if (c == '}')
            {
                lastLeftC--;
            }
        }
        
        return maps.toArray(new String[0]);
    }
    
    private Map<Integer, Character> getCommaIndex(String ori)
    {
        Map<Integer, Character> indexMap = new HashMap<Integer, Character>();
        char tempC = 'a';
        
        StringBuffer sb = new StringBuffer();
        List<Integer> sbint = new ArrayList();
        for (int index = 0; index < ori.length(); index++)
        {
            char c = ori.charAt(index);
            if (PubEnvUtil.equals(c, PubEnvUtil.COLON) || PubEnvUtil.equals(c, PubEnvUtil.COMMA))
            {
                sb.append(c);
                sbint.add(index);
            }
        }
        String oriNew = StringUtil.reverse(sb);
        sbint = (List<Integer>) CollectionUtil.reverse(sbint);
        for (int index = 0; index < oriNew.length(); index++)
        {
            char c = oriNew.charAt(index);
            if (PubEnvUtil.equals(c, PubEnvUtil.COMMA) && PubEnvUtil.equals(tempC, PubEnvUtil.COLON))
            {
                indexMap.put(sbint.get(index), c);
            }
            tempC = c;
        }
        
        return indexMap;
    }
    
    /**
     * *********************************************************** <br>
     * 说明： <br>
     * 
     * @param ori
     * @return <br>
     * @String <br>
     * @methods pers.bc.utils.pub.JsonUtilbc#removeBlack <br>
     * @author licheng <br>
     * @date Created on 2020年4月5日 <br>
     * @time 下午8:01:09 <br>
     * @version 1.0 <br>
     *          ************************************************************ <br>
     * @see <br>
     */
    private String removeBlack(String ori)
    {
        if (ori == null)
        {
            return null;
        }
        int shuangyhao = 0;// 考虑{}有可能在""里面
        boolean isblanck[] = new boolean[ori.length()];
        for (int index = 0; index < ori.length(); index++)
        {
            if (ori.charAt(index) == '\"' && shuangyhao == 0)
            {
                shuangyhao++;
                continue;
            }
            if (ori.charAt(index) == '\"' && shuangyhao == 1)
            {
                shuangyhao--;
                continue;
            }
            if (shuangyhao == 1)
            {
                continue;
            }
            if (// ori.charAt(index) == ' ' ||
            ori.charAt(index) == '\n' || ori.charAt(index) == '\t' || ori.charAt(index) == '\r')
            {
                isblanck[index] = true;
            }
        }
        StringBuilder sb = new StringBuilder("");
        for (int i = 0; i < ori.length(); i++)
        {
            if (!isblanck[i])
            {
                sb.append(ori.charAt(i));
            }
        }
        return sb.toString();
    }
    
}
